package com.globaldom.web;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.globaldom.model.Deployment;
import com.globaldom.model.MilResource;
import com.globaldom.model.Person;
import com.globaldom.model.PersonLocation;
import com.globaldom.model.Wars;
import com.globaldom.utils.Constants;
import com.globaldom.utils.EMF;
import com.globaldom.utils.MemCacheManager;
import com.globaldom.utils.SessionManager;

@Controller
@RequestMapping(value = "/war")
public class WarController {

	private static final Logger log = Logger.getLogger(WarController.class.getName());

	public WarController() {
	}

	@RequestMapping(method = RequestMethod.GET)
	public String getCreateForm(Model model, HttpSession session) {
		return "territory";
	}

	/*
	 * This is the main method for war. The use case of this method is as
	 * follows 1)Get player's free resources 2)Get enemys resourced deployed at
	 * this particular satellites 3)for each kind of military resource find out
	 * the difference d 4) Multiply d*hitpoint of that resource= totalpoint t
	 * 5)If t is -ve the player has lost else player has won 6)If player has
	 * lost a) if d is positive i)for each resource then update it to d else set
	 * it 0 ii)for each enemy resource at deployment update it to 0 else set it
	 * ABS(d) 7)If player has won a)update the owner of location to current
	 * player b)goto 6a
	 * 
	 * 
	 * If player wins: location captured with no deployment opponent remaining
	 * army freed for opponnet? or kill them all?
	 * 
	 * if player looses: remaining army in same free position opponent location
	 * decreased by casualty
	 * 
	 * eg Army 12 vs 15 (5hp) Tank 7 vs 5 ( 10 hp) Navy 19 vs 19 (12 hp) Sub 12
	 * vs 15 (20 hp)
	 * 
	 * A -3 T 2 N 0 S -3
	 * 
	 * (-3*5) + (2*10) + (0*15) + (-3*20) =-55 LOSS
	 */
	@RequestMapping(value = "/attackterritory", method = RequestMethod.POST)
	public String getAttackTerritory(@RequestParam String locID, @RequestParam String pid, Model model,
			HttpSession session, HttpServletRequest request) {
		String personID = SessionManager.getID(request, session);
		if(null==personID) 
			{
	
			return "loggedout";
			}

		EntityManager em = EMF.get().createEntityManager();

		try {
			PersonLocation enemyLocation = em.find(PersonLocation.class, locID);
			Person enemy = em.find(Person.class,pid);
			Person player = em.find(Person.class, personID);
	
			Query queryx = em.createQuery("Select pl from PersonLocation pl  where locationType=0 AND person=:pid");
			queryx.setParameter("pid", personID);
			PersonLocation homeLocation = (PersonLocation) queryx.getSingleResult();
//			List<Deployment> homeDeployment = homeLocation.getDeployment();

			Map<Integer, Long> freeMap;
			freeMap = MemCacheManager.getFreeResources(personID);

			if (null == freeMap) {
				freeMap = new HashMap<Integer, Long>();
//				for (Iterator<Deployment> iterator = homeDeployment.iterator(); iterator.hasNext();) {
//					Deployment freeDep = (Deployment) iterator.next();
//					freeMap.put(freeDep.getResourceType(), freeDep.getAvailResources());
//				}
				MemCacheManager.putFreeResources(personID, freeMap);
			}

			// get the enemy army at the deployment
			Map<Integer, Long> enemyLostUnit = new HashMap<Integer, Long>();
			int totalPoint = 1;
			// Iterate through the deployment and match up with players free
			// resources
			boolean flawlessVictory = true;
			//FIXME
			List<Deployment> enemyDeployment = new ArrayList();// enemyLocation.getDeployment();
			for (Iterator<Deployment> iterator = enemyDeployment.iterator(); iterator.hasNext();) {
				Deployment curDeployment = (Deployment) iterator.next();
				int unitType = curDeployment.getResourceType();
				long playerStrength = freeMap.get(Integer.valueOf(unitType));
				long enemyStrength = curDeployment.getAvailResources();
				long variance = playerStrength - enemyStrength;
				if (variance > 0) {
					enemyLostUnit.put(unitType, enemyStrength);
					model.addAttribute("cas"+unitType, enemyStrength);
				} else {
					enemyLostUnit.put(unitType, playerStrength);
					model.addAttribute("cas"+unitType, playerStrength);
				}
				// warMap.put(unitType, variance);
				totalPoint += (unitType + 1) * 5 * variance;
				flawlessVictory = false;
			}

			// Winner has been decided
			boolean win = totalPoint > 0;
			model.addAttribute("win", win);
		
			model.addAttribute("fw", flawlessVictory);
			if (!flawlessVictory) {
				// get the total army of the player
				List<MilResource> milResources = new ArrayList();// player.getMilResource();
				// update the losses for player regardless of outcome
				for (MilResource milResource : milResources) {
					Long leftOver = enemyLostUnit.get(milResource.getUnitType());
					// if (null == leftOver)continue;
					if (leftOver < 0)
						leftOver = 0l;
					milResource.setMilAvailable(milResource.getMilAvailable() - leftOver);
				}

				
				// AND then UPDATE THE HOME LOCATION TOO!
				
				

				// get the enemy and update his military resource too.
				List<MilResource> enmilResources = new ArrayList();//enemy.getMilResource();
				for (MilResource milResource : enmilResources) {
					// can enemyLost unit contain a null value here?
					long unitRemaining = milResource.getMilAvailable() - enemyLostUnit.get(milResource.getUnitType());
					milResource.setMilAvailable(unitRemaining);
				}
			}

			// Now decide the spoils
			if (win) {
				PersonLocation winlocation = new PersonLocation();
				winlocation.setLatitude(enemyLocation.getLatitude());
				winlocation.setLongitude(enemyLocation.getLongitude());
				winlocation.setLocationType(Constants.LocationType.SATELLITE.ordinal());
				winlocation.setDateCreated(new Date());
				winlocation.setPerson(player.getId());
				winlocation.setDistance(100);
				//player.getLocations().add(winlocation);
				MemCacheManager.addLocation(personID, winlocation);// WILL PURGE
																	// THE
																	// CACHE!
				MemCacheManager.removeLocation(pid, enemyLocation);// rem from
																	// cache
				em.remove(enemyLocation);// remove from the datastore

			} else {
				// we have friggin lost the battle. Update the deployed
				// resources for the enemy and then exit
				// subtract the remaining resources from the deployment
				Map<Integer, Long> enemyLeft = new HashMap<Integer, Long>();
				for (Iterator<Deployment> iterator = enemyDeployment.iterator(); iterator.hasNext();) {
					Deployment curDeployment = (Deployment) iterator.next();
					long unitRemaining = curDeployment.getAvailResources()
							- enemyLostUnit.get(curDeployment.getResourceType());
					curDeployment.setAvailResources(unitRemaining);
					enemyLeft.put(curDeployment.getResourceType(), curDeployment.getAvailResources());
				}

				MemCacheManager.putDeployment(pid, locID, enemyLeft);
			}

			em.persist(player);
			em.persist(enemy);
			// Save the war stats
			String enemyID = enemy.getId();
			EntityManager emwar = EMF.get().createEntityManager();
			Query qwar = emwar.createQuery("Select w from Wars w where personID=:person and enemyID=:enemy");
			qwar.setParameter("person", personID);
			qwar.setParameter("enemy", enemyID);
			List<Wars> wars = qwar.getResultList();
			Wars war;
			if (wars.size() == 0) {
				war = new Wars();
			} else {
				war = wars.get(0);
			}

			war.setPersonID(personID);
			war.setEnemyID(enemyID);
			war.setWarCount(war.getWarCount() + 1);
			emwar.persist(war);
			emwar.close();

			EntityManager emwarcount = EMF.get().createEntityManager();
			Query q = emwarcount.createQuery("Select w from Wars w where personID=:person");
			q.setParameter("person", personID);
			List<Wars> warcounts = q.getResultList();
			model.addAttribute("warcount", warcounts.size());
			model.addAttribute("enemy", enemyID);
			emwarcount.close();

		} catch (Exception ex) {
			log.severe("Severe Exception in War controller " + ex.getMessage());
		}

		finally {
			em.close();
		}

		return "aterritory";
	}

}
